My pemission is granted for anyone giving credit to Mark Welch and/or Geordie to use this however they please. If posting the tutorial, keep it whole. The code is open to play with and learn from.

This tutorial will add adjustable zoom to the sniper rifle. It's quite a lengthy and involved process, so bear with me :)

I'm assuming you've installed the SDK, extracted the source code and built a few minor mods already. If not, check out some of the other tutorials out there before you attempt this

rather than edit the origional classes, I'm going to add this mod as a new .u file. Those who want to edit the origional classes will hopefully know what they are doing ;). In particular, I'd be honoured if someone added this to the Universal Constructor Mod or similar. I found it invaluable :)

1) Make a new directory in the Deusex tree called ZoomWeapon. Add the subdirectory classes.

2) Add EditPackages=ZoomWeapon to the bottom of the EditPackages list in DeusEx.ini

3) in ZoomWeapon\classes create the file ZoomWeapon.uc

add

//=============================================================================
// Zoomable Sniper Rifle by Geordie mark_r_w@lineone.net
//=============================================================================


class ZoomWeapon extends DeusExWeapon
	abstract;

var() int ScopeMax;
var() int ScopeMin;

var int ScopeCurrent;

function InScope()
{
	if (bHasScope && (Owner != None) && Owner.IsA('DeusExPlayer'))
	{

		if(!bZoomed) // If not already zoomed in, zoom in
		{
			// Show the Scope View
			bZoomed = True;
			ScopeCurrent=ScopeMin;
			RefreshScopeDisplay(DeusExPlayer(Owner), False);

		}

		else // zoom in closer ( smaller ScopeCurrent values = closer FOV)

		{
			if (ScopeCurrent!=ScopeMax)
			{
				--ScopeCurrent;
				RefreshScopeDisplay(DeusExPlayer(Owner), False);
			}
		}
	}

}


function OutScope()
{
	if(bHasScope && bZoomed && (Owner != None) && Owner.IsA('DeusExPlayer') &&
 (ScopeCurrent!=ScopeMin) )
	{
		++ScopeCurrent;
		RefreshScopeDisplay(DeusExPlayer(Owner),False);
	}
}


function RefreshScopeDisplay(DeusExPlayer player, bool bInstant) 
// Copied straight from DeusExWeapon - only change is to use ScopeCurrent in place of ScopeFOV
{
	if (bZoomed && (player != None))
	{
		// Show the Scope View
		DeusExRootWindow(player.rootWindow).scopeView.ActivateView(ScopeCurrent, False, 
bInstant);
	}
}

defaultproperties
{
	ScopeMax=2;
	ScopeMin=10;

}
A few pointers here. This is an abstract class so we can easily add any number of weapons with the new scope by adding classes expanding ZoomWeapon. ScopeMax should be SMALLER than ScopeMin because of the way FOV is calculated. If it is larger, you just won't gain any variation - it will stick on ScopeMin. ScopeMax and ScopeMin are var() variables. This means that they are editable from the UnrealEd properties box. ScopeCurrent is internal, so it is an ordinary var variable.

4) Add our weapon. This is a straight cut&paste from WeaponSniperRifle with ScopeMax + ScopeMin tagged on the end :) Call it ZoomSniperRifle.uc

//=============================================================================
// Zoomable Sniper Rifle by Geordie (mark_r_w@lineone.net)
//=============================================================================
class ZoomSniperRifle extends ZoomWeapon;

defaultproperties
{
     LowAmmoWaterMark=6
     GoverningSkill=Class'DeusEx.SkillWeaponRifle'
     NoiseLevel=2.000000
     EnviroEffective=ENVEFF_Air
     ShotTime=1.500000
     reloadTime=2.000000
     HitDamage=25
     maxRange=48000
     AccurateRange=28800
     bCanHaveScope=True
     bHasScope=True
     bCanHaveLaser=True
     bCanHaveSilencer=True
     bHasMuzzleFlash=False
     recoilStrength=0.400000
     bUseWhileCrouched=False
     bCanHaveModBaseAccuracy=True
     bCanHaveModReloadCount=True
     bCanHaveModAccurateRange=True
     bCanHaveModReloadTime=True
     bCanHaveModRecoilStrength=True
     AmmoName=Class'DeusEx.Ammo3006'
     ReloadCount=6
     PickupAmmoCount=6
     bInstantHit=True
     FireOffset=(X=-20.000000,Y=2.000000,Z=30.000000)
     shakemag=50.000000
     FireSound=Sound'DeusExSounds.Weapons.RifleFire'
     AltFireSound=Sound'DeusExSounds.Weapons.RifleReloadEnd'
     CockingSound=Sound'DeusExSounds.Weapons.RifleReload'
     SelectSound=Sound'DeusExSounds.Weapons.RifleSelect'
     InventoryGroup=50
     ItemName="Sniper Rifle"
     PlayerViewOffset=(X=20.000000,Y=-2.000000,Z=-30.000000)
     PlayerViewMesh=LodMesh'DeusExItems.SniperRifle'
     PickupViewMesh=LodMesh'DeusExItems.SniperRiflePickup'
     ThirdPersonMesh=LodMesh'DeusExItems.SniperRifle3rd'
     LandSound=Sound'DeusExSounds.Generic.DropMediumWeapon'
     Icon=Texture'DeusExUI.Icons.BeltIconRifle'
     largeIcon=Texture'DeusExUI.Icons.LargeIconRifle'
     largeIconWidth=159
     largeIconHeight=47
     invSlotsX=4
     Description="The military sniper rifle is the superior tool for the interdiction of long-range targets. 
When coupled with the proven 30.06 round, a marksman can achieve tight groupings at better than 1 
MOA (minute of angle) depending on environmental conditions. Deicide Version"
     beltDescription="SNIPER"
     Mesh=LodMesh'DeusExItems.SniperRiflePickup'
     CollisionRadius=26.000000
     CollisionHeight=2.000000
     Mass=30.000000
     ScopeMax=5;
     ScopeMin=12;
}

5) We have the basic functionality for the zoom now, we just need to add the new functionality to our Player. Call the last file ZoomPlayer.uc

//=============================================================================
// ZoomPlayer by Geordie (mark_r_w@lineone.net)
//=============================================================================
class ZoomPlayer extends JCDentonMale;


// exec allows functions be tied to keypresses etc. in User.ini. These ones are called
// when the specified key is pressed

exec function ScopeIn()
{
	local ZoomWeapon W;

	if (RestrictInput())
		return;

	W = ZoomWeapon(Weapon);
	if (W != None)
		W.InScope();
}

exec function ScopeOut()
{
	local ZoomWeapon W;

	if (RestrictInput())
		return;

	W = ZoomWeapon(Weapon);
	if (W != None)
		W.OutScope();
}

These two functions simply call the relevant function in ZoomWeapon.uc. It is now usable (but not finished). If you are impatient, compile this and make the following changes to User.ini in Deusex\system

change Class=DeusEx.JCDentonMale to Class=ZoomWeapon.ZoomPlayer

assuming you will use PageUp and PageDown for zoom,

find both instances of PageUp= and add PageUp=ScopeIn

do the same with both PageDown=ScopeOut

when you run, you will need to use the cheats to summon ZoomWeapon.ZoomSniperRifle - the vanilla Deus Ex one hasn't been changed.

If you do try it at this point, you will find that it doesn't zoom in very smoothly - you need to hammer the zoom in key a few times to get to full zoom. Lets add the last bit

6) Open up ZoomPlayer

in between the class declaration and the first function, add

var input byte bScopeIn;

var input byte bScopeOut;

and in User.ini, find the Alises[] section, and add

Aliases[18]=(Command="Button bScopeIn | ScopeIn",Alias=ScopeIn)

Aliases[19]=(Command="Button bScopeOut | ScopeOut",Alias=ScopeOut)

to the first two free

Aliases[18]=(Command="",Alias=None)

Aliases[19]=(Command="",Alias=None)

lines (probably 18 and 19 :) there are two sections of Aliases[], and they need to match each other. MAKE SURE YOU EDIT BOTH, AND THAT THEY ARE THE SAME. I was tearing hair out trying to work out why this would work in UT but not DX :)

var input byte makes the engine map the state of a key or mouse button to the variable. So now bScopeIn will be 1 if the ScopeIn button is pressed, and 0 if it is depressed. The Aliases line sets the ScopeIn button we defined earlier to both call the exec function ScopeIn() and update bScopeIn.

7) Now, if we add a Tick function to ZoomWeapon to check if the keys are still held, it zooms in and out smoothly

simulated function Tick(float deltaTime)
{
	Super.Tick(deltaTime);

	if (ZoomPlayer(Owner).bScopeIn==1 && bZoomed)
	{
		InScope();
	}

	if (ZoomPlayer(Owner).bScopeOut==1 && bZoomed)
	{
		OutScope();
	}
}
8) Recompile, run DeusEx and give those MJ12 boys a headshot for me :)